package forwarder

import (
	"bytes"
	"encoding/json"
	"fmt"
	"github.com/user/linux-command/utils"
	"io"
	"net/http"
	"strings"
	"time"

	"github.com/user/linux-command/database"
	"github.com/user/linux-command/models"
)

// Forwarder 转发器
type Forwarder struct {
	Client *http.Client
}

// NewForwarder 创建新的转发器
func NewForwarder() *Forwarder {
	return &Forwarder{
		Client: &http.Client{
			Timeout: 30 * time.Second,
		},
	}
}

// ForwardRequest 转发JSON-RPC请求
func (f *Forwarder) ForwardRequest(rpcRequest *models.JSONRPCRequest) (*models.JSONRPCResponse, error) {
	// 解析方法名，提取工具名
	toolName := f.extractToolName(rpcRequest.Method)
	if toolName == "" {
		return f.createErrorResponse(rpcRequest.ID, -32601, "Method not found", nil), nil
	}
	if toolName == "tools/call" {
		//然后解析 params
		toolName1, ok := rpcRequest.Params.(map[string]interface{})["name"]
		if !ok {
			return f.createErrorResponse(rpcRequest.ID, -32601, "Method not found", nil), nil
		}
		toolName = toolName1.(string)
	}
	// 查找工具对应的服务
	tool, err := database.GetToolByName(toolName)
	if err != nil {
		return f.createErrorResponse(rpcRequest.ID, -32601, fmt.Sprintf("Tool '%s' not found", toolName), nil), nil
	}

	// 获取服务信息
	service, err := database.GetServiceByID(tool.ServiceID)
	if err != nil {
		return f.createErrorResponse(rpcRequest.ID, -32603, "Service not available", nil), nil
	}

	// 转发请求到目标服务
	return f.forwardToService(service.URL, rpcRequest)
}

// extractToolName 从方法名中提取工具名
func (f *Forwarder) extractToolName(method string) string {
	// 假设方法格式为 "tools/call/{toolName}" 或 "{toolName}"
	if strings.HasPrefix(method, "tools/call/") {
		return strings.TrimPrefix(method, "tools/call/")
	}
	return method
}

// forwardToService 转发请求到目标服务
func (f *Forwarder) forwardToService(serviceURL string, rpcRequest *models.JSONRPCRequest) (*models.JSONRPCResponse, error) {
	requestBody, err := json.Marshal(rpcRequest)
	if err != nil {
		return f.createErrorResponse(rpcRequest.ID, -32700, "Parse error", nil), nil
	}
	req, err := http.NewRequest("POST", serviceURL, bytes.NewBuffer(requestBody))
	if err != nil {
		return nil, err
	}
	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("Accept", "application/json, text/event-stream")
	resp, err := f.Client.Do(req)
	if err != nil {
		return f.createErrorResponse(rpcRequest.ID, -32000, "Service unavailable", nil), nil
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		return f.createErrorResponse(rpcRequest.ID, -32000, fmt.Sprintf("Service returned status: %d", resp.StatusCode), nil), nil
	}

	body, err := io.ReadAll(resp.Body)
	if err != nil {
		return f.createErrorResponse(rpcRequest.ID, -32603, "Internal error", nil), nil
	}
	//这里清洗数据
	b1 := string(body)
	b1 = utils.ExtractJSON(b1)
	var response models.JSONRPCResponse
	if err := json.Unmarshal([]byte(b1), &response); err != nil {
		return f.createErrorResponse(rpcRequest.ID, -32700, "Parse error", nil), nil
	}

	// 确保响应ID与请求ID一致
	response.ID = rpcRequest.ID
	return &response, nil
}

// createErrorResponse 创建错误响应
func (f *Forwarder) createErrorResponse(id interface{}, code int, message string, data interface{}) *models.JSONRPCResponse {
	return &models.JSONRPCResponse{
		JSONRPC: "2.0",
		Error: &models.RPCError{
			Code:    code,
			Message: message,
			Data:    data,
		},
		ID: id,
	}
}

// HandleToolsList 处理tools/list请求
func (f *Forwarder) HandleToolsList(requestID interface{}) *models.JSONRPCResponse {
	// 获取所有活跃的服务
	services, err := database.GetAllServices()
	if err != nil {
		return f.createErrorResponse(requestID, -32603, "Failed to get services", nil)
	}

	// 收集所有工具
	var allTools []models.ToolDefinition
	for _, service := range services {
		tools, err := database.GetToolsByService(service.ID)
		if err != nil {
			continue // 跳过有问题的服务
		}

		for _, tool := range tools {
			allTools = append(allTools, models.ToolDefinition{
				Name:        tool.Name,
				Description: tool.Description,
				InputSchema: tool.InputSchema,
			})
		}
	}

	return &models.JSONRPCResponse{
		JSONRPC: "2.0",
		Result: map[string]interface{}{
			"tools": allTools,
		},
		ID: requestID,
	}
}
